<template>
  <div @click.stop="" class="base-audio-wrapper">
    <div
      class="base-audio-wrapper-backer"
      :style="{ backgroundImage: `url('${songDetail.album.picUrl}')` }"
    ></div>
    <div class="base-audio-wrapper-body">
      <div class="base-audio-wrapper-body-top">
        <div class="body-top-left">
          <van-icon
            name="arrow-down"
            @click="closeMask"
            class="body-top-right"
          />
          <div class="body-top-left-info">
            <div>{{ songDetail.name }}</div>
            <div>{{ getSonger }}</div>
          </div>
        </div>
        <van-icon name="share-o" class="body-top-right" />
      </div>
      <div class="base-audio-wrapper-body-middle">
        <div class="middle-picture">
          <div class="middle-picture-img" :class="{ playing: playStatus }">
            <img
              v-if="songDetail.album.picUrl"
              :src="songDetail.album.picUrl"
              alt=""
            />
          </div>
        </div>
        <div class="middle-oprate">
          <div class="middle-oprate-btns">
            <div
              class="middle-oprate-btns-btn middle-oprate-btns-likebtn"
              :class="{ liked: haveFavorite }"
              @click="favOprate"
            ></div>
            <div
              @click="showCommend = true"
              class="middle-oprate-btns-btn middle-oprate-btns-commenbtn"
            ></div>
            <div
              @click="wordShow = true"
              class="middle-oprate-btns-btn middle-oprate-btns-gechi"
            ></div>
          </div>
          <div class="middle-opeate-slider">
            <div class="slider-time">
              {{ formatTimeByTimeStap(songCurrTime) }}
            </div>
            <div class="slider-body">
              <van-slider v-model="playProcess" @change="processChange" />
            </div>
            <div class="slider-time">
              {{ formatTimeByTimeStap(songDetail.duration) }}
            </div>
          </div>
        </div>
      </div>
      <div class="base-audio-wrapper-body-down">
        <div class="body-down-repeat"></div>
        <van-icon
          @click="playOrPause"
          class="body-down-icon"
          :name="`${playStatus ? 'pause' : 'play'}-circle-o`"
        />
      </div>
    </div>
    <audio id="playerAudio" :src="getMp3Url"></audio>
    <van-popup
      v-model:show="showCommend"
      position="bottom"
      :style="{ height: '85%' }"
    >
      <base-comment :songId="currentMusic.id"></base-comment>
    </van-popup>
    <van-popup
      v-model:show="wordShow"
      position="right"
      :style="{ width: '100%' }"
    >
      <base-lyric
        :ref="(el) => (lyricRef = el)"
        :songId="currentMusic.id"
        :closeLyric="closeLyric"
      ></base-lyric>
    </van-popup>
  </div>
</template>

<script lang='ts'>
import {
  defineComponent,
  reactive,
  toRefs,
  computed,
  watch,
  onMounted,
} from "vue";
import { httpService } from "@/core/http";
import api from "@/api";
import { getMp3UrlById } from "@/utils/tips";
import dayjs from "dayjs";
import { useStore } from "vuex";
import BaseComment from "./base_comment.vue";
import BaseLyric from "./base_lyric.vue";
import storage, { EStorage } from "@/core/storage";

export interface IBaseAudioProps {
  /** 歌曲id */
  id?: string;
  /** 关闭音乐播放器蒙层 */
  closeMask: () => void;
}

export default defineComponent({
  name: "BaseAudio",
  props: {
    closeMask: {
      type: Function,
      default: () => new Function(),
    },
    /** 当前播放音乐 */
    currentMusic: {
      type: Object,
      default: () => ({}),
    },
  },
  components: {
    BaseComment,
    BaseLyric,
  },
  setup(props: IBaseAudioProps | any) {
    const $store = useStore();
    const state = reactive({
      /** 音屏实例 */
      audioInstance: document.createElement("audio"),
      /** 播放/暂停 */
      playStatus: false,
      /** 播放进度 */
      playProcess: 0,
      /** 歌曲信息，http请求获取 */
      songDetail: {
        name: "歌曲名称",
        artists: [{ name: "歌手名称" }],
        mvid: "",
        duration: 0,
        album: {
          name: "专辑名称",
          picUrl: "",
          company: "音乐公司",
        },
      },
      /** 当前播放时间 */
      songCurrTime: 0,
      /** 是否展示评论 */
      showCommend: false,
      /** 是否展示歌词 */
      wordShow: false,
      /** 歌词组件实例 */
      // eslint-disable-next-line @typescript-eslint/no-unused-vars
      lyricRef: {
        positionCurrentTimeLyric: (time: number) => {
          return;
        },
      },
      /** 是否收藏了这首歌  */
      haveFavorite: false,
    });
    onMounted(() => {
      const audioDom = document.querySelector(
        "#playerAudio"
      ) as HTMLAudioElement;
      audioDom && (state.audioInstance = audioDom);
    });
    /** 修改播放进度 */
    const processChange = (process: number) => {
      const timeStamp = (process / 100) * state.songDetail.duration;
      state.audioInstance.currentTime = timeStamp / 1000;
      state.playStatus = true;
    };
    /** 初始化音乐播放器 */
    const initMusicPlayer = () => {
      resetPlayer();
      /** 音乐可以播放触发 */
      state.audioInstance.addEventListener(
        "canplaythrough",
        canplayEvent,
        false
      );
      /** 音乐播放时触发 */
      state.audioInstance.addEventListener("timeupdate", playingEvent, false);
      /** 音乐播放完毕时触发 */
      state.audioInstance.addEventListener("ended", endedEvent, false);
      getMusicDetail(props.currentMusic?.id || "");
      /** 判断这首歌是否被收藏 */
      const likeMusicList = storage.get(EStorage.favMusicList) || [];
      const index = likeMusicList.findIndex(
        (op: any) => op.id === props.currentMusic?.id
      );
      state.haveFavorite = index !== -1;
    };
    /** 可以播放监听事件 */
    const canplayEvent = () => {
      state.songDetail.duration = state.audioInstance.duration * 1000;
      if (props.currentMusic?.isPlaying) {
        state.audioInstance.play();
        state.playStatus = true;
      }
    };
    /** 播放时监听事件 */
    const playingEvent = () => {
      timeupdateChange(state.audioInstance.currentTime * 1000);
    };
    /** 播放结束时监听事件 */
    const endedEvent = () => {
      state.playStatus = false;
      state.playProcess = 0;
      state.songCurrTime = 0;
    };
    /** 重置音乐播放器 */
    const resetPlayer = () => {
      state.audioInstance.removeEventListener("canplaythrough", canplayEvent);
      state.audioInstance.removeEventListener("timeupdate", playingEvent);
      state.audioInstance.removeEventListener("ended", endedEvent);
    };
    /** 音乐播放时间变化触发方法 */
    const timeupdateChange = (timeStamp: number) => {
      state.lyricRef && state.lyricRef.positionCurrentTimeLyric(timeStamp);
      const process = Math.floor((timeStamp / state.songDetail.duration) * 100);
      state.songCurrTime = timeStamp;
      state.playProcess = process;
    };
    /** 获取歌曲详情 */
    const getMusicDetail = (id: string) => {
      if (!id) return;
      httpService("GET", api.getMusicDetailById, { id, ids: `[${id}]` }).then(
        (res: any) => {
          if (res.songs && res.songs.length) {
            state.songDetail = res.songs[0];
          }
        }
      );
    };
    /** 获取当前歌的歌手 */
    const getSonger = computed<string>(() => {
      let songers = "";
      state.songDetail.artists.forEach((songer: any) => {
        songers += "/" + songer.name;
      });
      songers = songers.slice(1);
      return songers;
    });
    /** 获取当前歌曲mp3的url */
    const getMp3Url = computed(() =>
      getMp3UrlById(props.currentMusic?.id || "")
    );
    /** 根据毫秒数获取时间 0:00 */
    const formatTimeByTimeStap = computed(() => {
      return (timeStap: number) => {
        const day = dayjs(timeStap);
        return day.minute() + ":" + String(day.second()).padStart(2, "0");
      };
    });
    /** 播放歌曲 */
    const playSong = () => {
      if (!state.playStatus && state.audioInstance) {
        state.playStatus = true;
        state.audioInstance.play();
        $store.commit("setCurrentMusicPlayStaus", true);
      }
    };
    /** 暂停歌曲 */
    const pauseSong = () => {
      if (state.playStatus && state.audioInstance) {
        state.playStatus = false;
        state.audioInstance.pause();
        $store.commit("setCurrentMusicPlayStaus", false);
      }
    };
    /** 用户播放暂停操作 */
    const playOrPause = () => {
      state.playStatus ? pauseSong() : playSong();
    };
    /** 关闭歌词popup */
    const closeLyric = () => (state.wordShow = false);
    /** 收藏/取消收藏 */
    const favOprate = () => {
      if (state.haveFavorite) removeFavThisMusic();
      else favThisMusic();
    };
    /** 收藏歌曲 */
    const favThisMusic = () => {
      const likedMusicList = storage.get(EStorage.favMusicList) || [];
      if (!likedMusicList.find((op: any) => op.id === props.currentMusic.id)) {
        storage.set(
          EStorage.favMusicList,
          likedMusicList.concat(props.currentMusic)
        );
        state.haveFavorite = true;
      }
    };
    /** 取消收藏这首歌曲 */
    const removeFavThisMusic = () => {
      const likedMusicList = storage.get(EStorage.favMusicList) || [];
      if (likedMusicList.find((op: any) => op.id === props.currentMusic.id)) {
        likedMusicList.splice(
          likedMusicList.findIndex(
            (op: any) => op.id === props.currentMusic.id
          ),
          1
        );
        storage.set(EStorage.favMusicList, likedMusicList);
        state.haveFavorite = false;
      }
    };
    /** 监听音乐变化 */
    watch(
      () => props.currentMusic,
      (newVal, oldVal) => {
        if (oldVal) {
          newVal.id !== oldVal.id && initMusicPlayer();
        } else {
          initMusicPlayer();
        }
      }
    );
    return {
      ...toRefs(state),
      processChange,
      getSonger,
      getMp3Url,
      formatTimeByTimeStap,
      playSong,
      pauseSong,
      playOrPause,
      timeupdateChange,
      initMusicPlayer,
      closeLyric,
      favThisMusic,
      removeFavThisMusic,
      favOprate,
    };
  },
});
</script>

<style lang='scss'>
.base-audio-wrapper {
  width: 100%;
  height: 100%;
  position: relative;
  &-backer {
    position: absolute;
    top: 0;
    right: 0;
    left: 0;
    bottom: 0;
    background-size: cover;
    background-color: #ccc;
    filter: blur(15px);
    background-position: center center;
    background-repeat: no-repeat;
    content: "";
  }
  .base-audio-wrapper-body {
    position: absolute;
    width: 100%;
    height: 100%;
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    align-items: center;
    padding: 15px;
    box-sizing: border-box;
    & > div {
      width: 100%;
    }
    .base-audio-wrapper-body-top {
      height: 40px;
      display: flex;
      justify-content: space-between;
      .body-top-left {
        flex: 1;
        height: 100%;
        display: flex;
        justify-content: flex-start;
        align-items: center;
        .body-top-left-info {
          margin-left: 10px;
          div {
            color: #fff;
            font-weight: bold;
            &:last-child {
              font-size: 12px;
              font-weight: 500;
            }
          }
        }
      }
      .body-top-right {
        font-size: 30px;
        color: #fff;
        display: flex;
        justify-content: center;
        align-items: center;
      }
    }
    .base-audio-wrapper-body-middle {
      flex: 1;
      .middle-picture {
        height: calc(100% - 80px);
        display: flex;
        justify-content: center;
        align-items: center;
        .middle-picture-img {
          width: 220px;
          height: 220px;
          background: #fff;
          border-radius: 50%;
          overflow: hidden;
          @include systemBoxShaowStyle(0px,0px,80px);
          img {
            width: 100%;
            height: 100%;
          }
          @keyframes rotate {
            0% {
              transform: rotate(0deg);
            }
            100% {
              transform: rotate(360deg);
            }
          }
          &.playing {
            animation: rotate infinite 15s linear;
          }
        }
      }
      .middle-oprate {
        height: 80px;
        padding: 0 20px;
        .middle-oprate-btns {
          display: flex;
          justify-content: center;
          align-items: center;
          margin-bottom: 20px;
          .middle-oprate-btns-btn {
            width: 25px;
            height: 25px;
            margin: 10px 15px;
            background-size: 100% 100%;
            background-repeat: no-repeat;
          }
          .middle-oprate-btns-likebtn {
            background-image: url("../assets/images/like_white.svg");
            &.liked {
              background-image: url("../assets/images/like_red.svg");
            }
          }
          .middle-oprate-btns-commenbtn {
            background-image: url("../assets/images/commend.svg");
          }
          .middle-oprate-btns-gechi {
            background-image: url("../assets/images/gechi.svg");
          }
        }
        .middle-opeate-slider {
          display: flex;
          justify-content: space-between;
          align-items: center;
          .slider-time {
            width: 30px;
            text-align: left;
            color: #fff;
            font-size: 12px;
            font-weight: 600;
            &:last-child {
              text-align: right;
            }
          }
          .slider-body {
            flex: 1;
            margin: 0 10px;
          }
        }
        .van-slider__bar {
          @include systemBackColor();
        }
        .van-slider__button {
          width: 15px;
          height: 15px;
        }
      }
    }
    .base-audio-wrapper-body-down {
      height: 60px;
      display: flex;
      justify-content: space-between;
      align-items: center;
      .body-down-repeat {
        width: 36px;
        height: 36px;
        background-image: url("../assets/images/repeat.svg");
        background-repeat: no-repeat;
        background-size: 100% 100%;
        transform: translate(0, 3px);
      }
      .body-down-icon {
        color: #fff;
        font-size: 35px;
        display: flex;
        justify-content: center;
        align-items: center;
      }
    }
  }
  .van-popup--bottom {
    border-top-left-radius: 10px;
    border-top-right-radius: 10px;
  }
  .van-popup--right {
    height: 100%;
    background: rgba(0, 0, 0, 0.4);
  }
}
</style>